﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OMap {
    /// <summary>
    /// Interface for all ObjectMappers
    /// </summary>
    public interface IObjectMapper<in TSource,TTarget> : IObjectMapper {


    	/// <summary>
    	/// Maps from the passed source object into a new target object.
    	/// </summary>
    	/// <param name="source">The source object that should be mapped into a new target object.</param>
    	/// <param name="referenceDict">The reference dict.</param>
    	/// <returns></returns>
    	TTarget MapTo(TSource source, Dictionary<object, object> referenceDict);

    	/// <summary>
    	/// Maps from the passed source object into an existing target object.
    	/// </summary>
    	/// <param name="source">The source object that should be mapped into a new target object.</param>
    	/// <param name="target">The target object that should be used as mapping target.</param>
    	/// <param name="referenceDict">The reference dict.</param>
    	/// <returns></returns>
    	TTarget MapTo(TSource source, TTarget target, Dictionary<object, object> referenceDict);

    }

    /// <summary>
    /// Interface for all ObjectMapper.
    /// </summary>
    public interface IObjectMapper {
		/// <summary>
		/// Gets the type of the target.
		/// </summary>
		/// <value>The type of the target.</value>
        Type TargetType { get;}

		/// <summary>
		/// Gets the type of the source.
		/// </summary>
		/// <value>The type of the source.</value>
        Type SourceType { get;}

		/// <summary>
		/// Gets the mapped source value.
		/// </summary>
		/// <value>The mapped source value.</value>
		object MappedSourceValue { get;
		}

		/// <summary>
		/// Gets the mapped target value.
		/// </summary>
		/// <value>The mapped target value.</value>
		object MappedTargetValue {
			get; set;
		}

		/// <summary>
		/// Gets the mapper that was calling the current mapper.
		/// </summary>
		IObjectMapper CalledBy {
			get; set;
		}

    	/// <summary>
    	/// Defines the Logic that should be executed to create a new target object.
    	/// </summary>
    	/// <value></value>
    	Func<IObjectMapper, object> CreateTarget{ get; set;}

		/// <summary>
		/// Maps from the passed source object into a new target object.
		/// </summary>
		/// <param name="source">The source object that should be mapped into a new target object.</param>
		/// <param name="referenceDict">The reference dict.</param>
		/// <returns></returns>
        object MapTo(object source,Dictionary<object, object> referenceDict);


		/// <summary>
		/// Maps from the passed source object into an existing target object.
		/// </summary>
		/// <param name="source">The source object that should be mapped into a new target object.</param>
		/// <param name="target">The target object that should be used as mapping target.</param>
		/// <param name="referenceDict">The reference dict.</param>
		/// <returns></returns>
        object MapTo(object source, object target,Dictionary<object, object> referenceDict);


		/// <summary>
		/// Initializes the specified Root Mapping Object <see cref="OMap"/>.
		/// </summary>
		/// <param name="oMap">The root mapping object.</param>
    	void Initialize(OMap oMap);

		/// <summary>
		/// Determines whether the current mapper is already initialized or not.
		/// </summary>
		bool IsInitialized { get; }



		/// <summary>
		/// Defines if existing value in the target value should be overwritten if they are none default values.
		/// E.g. if in the target is null the null will be always overwritten, but if there is already a value
		/// it won't be set unless this property was set to true.
		/// </summary>
		/// <remarks>
		/// Please note that if you are using collections and if the collection have already been initialized
		/// (value is not null) and do not have any values inside the collection this value wont be overwritten by the source value if this property was
		/// not set to true.
		/// </remarks>
		bool OverwriteTarget { get;}
    }
}
